import {
	dclassMap,
	dclassCodeMap,
	resourceBaseUrl,
	ASCII
} from './constant'
import {
	isNumber,
	getHunterAlarmInfo,
	unsignToSign,
	parseTime,
	getDateDiff
} from './index'
const boolEnums = ['true', true, '"true"', 1, '1', 1.0, '1.0', 255, '255.0']

/**
 * 获取设备实时状态
 * @param {*} value
 * @param {*} rtuPortDisplay
 * @returns
 */
export function getDeviceState(value, rtuPortDisplay, states) {
	let result = rtuPortDisplay.default_val
	if (rtuPortDisplay.datatype === 'enum') {
		result = getDeviceEnumState(rtuPortDisplay, states)
	} else if (rtuPortDisplay.datatype === 'mix') {
		const expression = JSON.parse(rtuPortDisplay.expression)
		result = ''
		expression.forEach((item) => {
			result += parseInt(states && states[item.namekey] || 0) + item.unit
		})
	} else if (rtuPortDisplay.datatype === 'pwmNew') {
		if (states) {
			const idx = rtuPortDisplay.namekey.split('_')[1]
			let p1 = states['p' + idx] || 0
			p1 = p1 + '%'
			let d1 = states['d' + idx] || 0
			d1 = d1 + 's'

			return p1 + ' | ' + d1
		}
		return ''
	} else {
		try {
			if (value !== undefined) {
				if (rtuPortDisplay.namekey === 'Info') {
					result = getHunterAlarmInfo(value, 'info') || 0
				} else if (rtuPortDisplay.namekey === 'Alarm') {
					result = getHunterAlarmInfo(value, 'alarm') || 0
				} else {
					switch (rtuPortDisplay.datatype) {
						case 'int':
						case 'float':
							if (rtuPortDisplay.expression) {
								const format = JSON.parse(rtuPortDisplay.expression)
								const operator = format.operator
								const val = format.value
								const names = format.names
								result = value
								if (operator === '>') {
									result = value > val ? names[1] : names[0]
								} else if (operator === '&') {
									result = value & val ? names[1] : names[0]
								}
							} else {
								if (typeof(value) === 'string') {
									value = value.replace(/"/g, '')
								}
								result = value !== undefined ? (Number(value) * (rtuPortDisplay.kunit)).toFixed(
									rtuPortDisplay.fmt) : '--'
							}
							break
						case 'floatSign':
							if (typeof(value) === 'string') {
								value = value.replace(/"/g, '')
							}
							value = unsignToSign(value)
							result = value !== undefined ? (Number(value) * (rtuPortDisplay.kunit)).toFixed(
								rtuPortDisplay.fmt) : '--'
							break
						case 'bool':
							value = boolEnums.includes(value) ? 1 : 0
							result = rtuPortDisplay.bool_format_arr.split(',')[value]
							break
						case 'string':
							result = value.replace(/"/g, '')
							break
						case 'pwm':
							result = getPwmInfo(value)
							break
						default:
							result = value
							break
					}
				}
			} else {
				if (['int', 'float'].includes(rtuPortDisplay.datatype)) {
					result = 0
				}
			}
			// eslint-disable-next-line no-empty
		} catch (err) {}

		return result
	}

	function getDeviceEnumState(rtuPortDisplay, states) {
		const enums = JSON.parse(rtuPortDisplay.bool_format_arr)
		const namekeys = enums.namekeys
		const values = enums.values
		const length = namekeys.length

		if (values.length > namekeys.length) {
			return values[parseInt(states[namekeys[0]])]
		} else {
			for (let i = 0; i < length; i++) {
				if (i < length - 1) {
					if (Object.prototype.hasOwnProperty.call(states, namekeys[i]) && boolEnums.includes(states[namekeys[
							i]])) {
						return values[i]
					}
				} else {
					return values[i]
				}
			}
		}
	}

	return result
}

/**
 * 将设备以dclass分组
 * @param {*} devices
 * @returns
 */
export function getDclasses(devices) {
	const map = {}
	const result = []
	devices = devices.filter(val => {
		return +val.status === 1 || +val.product_type === dclassCodeMap.fkq
	})
	for (const item of devices) {
		if (!map[item.product_type]) {
			result.push({
				dclass: item.product_type,
				dclassName: dclassMap[item.product_type].name || '',
				data: [item]
			})
			map[item.product_type] = item
		} else {
			for (var j = 0; j < result.length; j++) {
				var dj = result[j]
				if (dj.dclass === item.product_type) {
					dj.data.push(item)
					break
				}
			}
		}
	}
	return result
}

/**
 * 格式化设备最后采集时间
 * @param {*} value
 * @returns
 */
export function getDatatime(value, states) {
	if (value) {
		const currentYear = value.substr(0, 4)
		if (currentYear != new Date().getFullYear()) {
			return value.substr(0, 10)
		}
		const currentDate = value.substr(5, 5)
		const currentTime = value.substr(11)

		var date = new Date()
		let month = date.getMonth() + 1
		let day = date.getDate()

		month = month < 10 ? '0' + month : month
		day = day < 10 ? '0' + day : day

		if (currentDate === month + '-' + day) {
			return currentTime
		}

		return currentDate
	}

	return '01-01'
}

/**
 * 显示弹出视频框
 * @param {*} serialno
 * @param {*} validCode
 * @param {*} accessToken
 */
export function showVideo(serialno, validCode, accessToken) {
	const url =
		`https://open.ys7.com/ezopen/h5/live?autoplay=1&audio=1&validCode=${validCode}&accessToken=${accessToken}&hd=1&deviceSerial=${serialno}&channelNo=1`
	window.open(url, '_blank', 'width=600,height=400')
}

/**
 * 显示设备的实时状态
 * @param {*} device
 * @returns
 */
export function getDeviceStatus(device, statusMapProps = null) {
	let status = 'd_break'
	const states = device.states || {}
	let isOffline = true
	const now = parseTime(new Date().getTime())
	if (states.datatime) {
		isOffline = getDateDiff(states.datatime, now, 'hour') > 4
	}

	const version = device.product.model.replace('.0', '')
	if (!statusMapProps && !device.status_map) {
		switch (+device.product_type) {
			case dclassCodeMap.qxz:
			case dclassCodeMap.sqz:
			case dclassCodeMap.gcwd:
			case dclassCodeMap.gd:
			case dclassCodeMap.ndvi:
			case dclassCodeMap.gps:
			case dclassCodeMap.cqz:
			case dclassCodeMap.zyp:
			case dclassCodeMap.gdgcwd:
			case dclassCodeMap.hjjc:
			case dclassCodeMap.wg:
				if (isOffline) {
					status = 'd_break'
				} else {
					if ((states.status && states.status === 'online') || !isOffline) {
						status = 'd_run'
					}
				}
				break
			case dclassCodeMap.zk:
				if ((states.status && states.status === 'online') || !isOffline) {
					if (boolEnums.includes(states.Fault)) {
						status = 'd_trouble'
					} else {
						status = 'd_close'
						if (boolEnums.includes(states.Lifting) || boolEnums.includes(states.Falling)) {
							status = 'd_run'
						}
					}
				}
				break
			case dclassCodeMap.qf:
				if (version === 'V1') {
					if (states.datatime && getDateDiff(states.datatime, now, 'hour') <
						24) {
						status = 'd_run'
						if (states.VPercent < 75) {
							status = 'd_v_2'
						}
						if (states.VPercent < 50) {
							status = 'd_v_3'
						}
						if (states.VPercent < 25) {
							status = 'd_v_4'
						}
					} else {
						status = 'd_break'
					}
				}
				if (version === 'V2') {
					if (states.datatime && getDateDiff(states.datatime, now, 'hour') <
						24) {
						status = 'd_run'
						if (states.VPercent < 75) {
							status = 'd_v_2'
						}
						if (states.VPercent < 50) {
							status = 'd_v_3'
						}
						if (states.VPercent < 25) {
							status = 'd_v_4'
						}
					} else {
						status = 'd_break'
					}
				}
				break
			case dclassCodeMap.spjk:
				status = 'd_run'
				break
			case dclassCodeMap.pg:
				if (version === 'V1') {
					if (states.status === 'online') {
						if (boolEnums.includes(states.SafeCircuit_State)) {
							status = 'd_trouble'
						} else if (boolEnums.includes(states.Forward_HMI) || boolEnums.includes(states.Backward_HMI)) {
							status = boolEnums.includes(states.Forward_HMI) ? 'd_forward' : 'd_reverse'
						} else {
							status = 'd_close'
						}
					}
				}
				if (version === 'V2' || version === 'V4') {
					if (states.status === 'online' && !isOffline) {
						const forward_sta = states.forward_sta
						const reverse_sta = states.reverse_sta
						const systemRun = (forward_sta === true || +forward_sta === 255) || (reverse_sta === true || +
							reverse_sta === 255) || forward_sta === undefined || reverse_sta === undefined
						if (systemRun && boolEnums.includes(states.TROUBLE_HMI)) {
							status = 'd_trouble'
						} else if (boolEnums.includes(states.FWD_HMI) || boolEnums.includes(states.REV_HMI)) {
							status = boolEnums.includes(states.FWD_HMI) ? 'd_forward' : 'd_reverse'
						} else {
							status = boolEnums.includes(states.System_Run) ? 'd_run' : 'd_close'
						}
					}
				}
				if (version === 'V3') {
					if (states.status === 'online') {
						if (boolEnums.includes(states.SafeCircuit_State)) {
							status = 'd_trouble'
						} else if (boolEnums.includes(states.Fwd_Sta) || boolEnums.includes(states.Bwd_Sta)) {
							status = boolEnums.includes(states.Fwd_Sta) ? 'd_forward' : 'd_reverse'
						} else {
							status = 'd_close'
						}
					}
				}
				break
			case dclassCodeMap.sb:
				if (version === 'V1') {
					if (states.status === 'online') {
						if (boolEnums.includes(states.fault1) || boolEnums.includes(states.fault2)) {
							status = 'd_trouble'
						} else {
							status = (boolEnums.includes(states.running1)) || (boolEnums.includes(states.running2)) ?
								'd_run' : 'd_close'
						}
					}
				}
				if (version === 'V2') {
					if (states.status === 'online') {
						if (boolEnums.includes(states.TROUBLE_HMI || states.a4 > 3000)) {
							status = 'd_trouble'
						} else {
							status = boolEnums.includes(states.RUN_HMI || Boolean((states.DO || 0) & 4)) ? 'd_run' :
								'd_close'
						}
					}
				}
				if (version === 'V4') {
					if (states.status === 'online') {
						if (boolEnums.includes(states.StatErr)) {
							status = 'd_trouble'
						} else {
							status = boolEnums.includes(states.StatRun) ? 'd_run' : 'd_close'
						}
					}
				}
				if (version === 'V5') {
					if (!isOffline) {
						if (boolEnums.includes(states.水泵故障)) {
							status = 'd_trouble'
						} else {
							status = boolEnums.includes(states.水泵运行) ? 'd_run' : 'd_close'
						}
					}
				}
				break
			case dclassCodeMap.sf:
				if (version === 'V1') {
					if (states.status === 'online') {
						status = (boolEnums.includes(states.fertiStart)) ? 'd_run' : 'd_close'
					}
				}
				if (version === 'V2') {
					if (states.status === 'online') {
						status = (boolEnums.includes(states.FertPump_State)) ? 'd_run' : 'd_close'
					}
				}
				if (version === 'V3') {
					if (states.status === 'online') {
						status = (boolEnums.includes(states.FertPump_State)) ? 'd_run' : 'd_close'
					}
				}
				if (version === 'V4') {
					if (states.datatime && getDateDiff(states.datatime, now, 'hour') <
						6) {
						status = (boolEnums.includes(states.注肥启停)) ? 'd_run' : 'd_close'
					}
				}
				break
			case dclassCodeMap.fm:
				status = (boolEnums.includes(states.DO)) ? 'd_run' : 'd_close'
				break
			case dclassCodeMap.df:
				if (version === 'V1') {
					status = 'd_break'
					if (states.status === 'online') {
						let OpenStat = states.OpenStat
						let CloseStat = states.CloseStat
						if (states.DI) {
							OpenStat = !Boolean(states.DI & 1)
							CloseStat = !Boolean(states.DI & 2)
						}
						if (boolEnums.includes(OpenStat) || boolEnums.includes(CloseStat)) {
							if (boolEnums.includes(OpenStat)) {
								status = 'd_run'
							}
							if (boolEnums.includes(CloseStat)) {
								status = 'd_close'
							}
						} else {
							status = 'd_pause'
						}
					}
				}
				if (version === 'V2') {
					if (isOffline) {
						status = 'd_break'
					} else {
						const a1 = +states.a1
						const a2 = +states.a2
						if([1,2].includes(a1) || [1,2].includes(a2)){
							status = 'd_run'
						} else if([0,3].includes(a1) || [0,3].includes(a2)){
							status = 'd_pause'
						} else {
							status = 'd_trouble'
						}
					}
				}
				break
			case dclassCodeMap.fkq:
				if (version === 'V1') {
					status = states.DO && Number(states.DO) > 0 ? 'd_run' : 'd_close'
					const DO1 = boolEnums.includes(states['DO.0']) ? 1 : 0
					const DO2 = boolEnums.includes(states['DO.1']) ? 1 : 0
					const DO3 = boolEnums.includes(states['DO.2']) ? 1 : 0
					const DO4 = boolEnums.includes(states['DO.3']) ? 1 : 0
					status = `${DO1}${DO2}${DO3}${DO4}`
				}
				if (version === 'V2') {
					status = 'd_close'
					if (states && (states.DO & 8 || states.DO & 12)) {
						status = 'd_run'
					}
					const DO3 = (states.DO & 4) > 0 ? 1 : 0
					const DO4 = (states.DO & 8) > 0 ? 1 : 0

					let a3 = 0
					if (states && states.a3) {
						const a3Number = Number(states.a3)
						if (a3Number >= 100 && a3Number <= 3000) {
							a3 = 2
						}
						if (a3Number > 3000) {
							a3 = 1
						}
						if (a3Number < 100) {
							a3 = 0
						}
					}
					let a4 = 0
					if (states && states.a4) {
						const a4Number = Number(states.a4)
						if (a4Number >= 100 && a4Number <= 3000) {
							a4 = 2
						}
						if (a4Number > 3000) {
							a4 = 1
						}
						if (a4Number < 100) {
							a4 = 0
						}
					}
					return `${DO3}${DO4}${a3}${a4}`
				}
				if (version === 'V3') {
					const GateCtrlStat = states.GateCtrlStat || 0
					const GateStat = states.GateStat || 0

					return `${GateCtrlStat}${GateStat}`
				}
				if (version === 'V4') {
					const DO1 = boolEnums.includes(states['电磁阀1']) ? 1 : 0
					const DO2 = boolEnums.includes(states['电磁阀2']) ? 1 : 0
					const DO3 = boolEnums.includes(states['电磁阀3']) ? 1 : 0
					const DO4 = boolEnums.includes(states['电磁阀4']) ? 1 : 0
					status = `${DO1}${DO2}${DO3}${DO4}`
				}
				if (version === 'V5') {
					status = states.DO && Number(states.DO) > 0 ? 'd_run' : 'd_close'
					const DO1 = states['DO'] & 1 ? 1 : 0
					const DO2 = states['DO'] & 2 ? 1 : 0
					const DO3 = states['DO'] & 4 ? 1 : 0
					const DO4 = states['DO'] & 8 ? 1 : 0
					status = `${DO1}${DO2}${DO3}${DO4}`
				}
				if (version === 'V6') {
					status = states.DO && Number(states.DO) > 0 ? 'd_run' : 'd_close'
					const DO1 = boolEnums.includes(states['CH1_SW']) ? 1 : 0
					const DO2 = boolEnums.includes(states['CH2_SW']) ? 1 : 0
					const DO3 = boolEnums.includes(states['CH3_SW']) ? 1 : 0
					const DO4 = boolEnums.includes(states['CH4_SW']) ? 1 : 0
					let a1 = 0
					if (states && states.a1) {
						const a1Number = Number(states.a1)
						if (a1Number >= 100 && a1Number <= 3000) {
							a1 = 2
						}
						if (a1Number > 3000) {
							a1 = 1
						}
						if (a1Number < 100) {
							a1 = 0
						}
					}
					let a2 = 0
					if (states && states.a2) {
						const a2Number = Number(states.a2)
						if (a2Number >= 100 && a2Number <= 3000) {
							a2 = 2
						}
						if (a2Number > 3000) {
							a2 = 1
						}
						if (a2Number < 100) {
							a2 = 0
						}
					}
					status = `${DO1}${DO2}${a1}${a2}`
				}
				break
			case dclassCodeMap.dg:
				status = 'd_close'
				break
		}
	} else {
		const status_map = statusMapProps || device.status_map
		if (status_map.d_run) {
			status = states[status_map.d_run] && boolEnums.includes(states[status_map.d_run]) ? 'd_run' : 'd_close'
		}
		if (status_map.d_trouble) {
			const status_map_trouble_arr = status_map.d_trouble.split(',')
			status_map_trouble_arr.forEach((item) => {
				if (item.indexOf('Alarm') > -1) {
					const value = (+states[item]).toString(2).padStart(16, 0)
					const res = createArr(value, 0, 4, 4)
					const alarms = ['0010', '0011', '0100']
					const alarm = alarms.includes(res[0]) || alarms.includes(res[1]) || alarms.includes(res[
						2]) || alarms.includes(res[3])
					if (alarm) {
						status = 'd_trouble'
					}
				} else {
					if (boolEnums.includes(states[item])) {
						status = 'd_trouble'
					}
				}
			})
		}
	}

	return status
}

export function getDeviceEnumValues(device) {
	const rtuPortDisplays = device.rtuPortDisplays.filter(val => {
		return val.datatype === 'enum'
	})
}

/**
 * 给设备加上最新状态
 * @param {*} devices
 * @param {*} states
 * @returns
 */
export function mergeDevicesStates(devices, states) {
	devices.map(item => {
		item.states = Object.assign(item.states, states[item.serialno])
	})

	return devices
}

/**
 * 获取设备对应状态图片
 * @param {*} currentDevice
 */
export function getDeviceImage(currentDevice) {
	return `${resourceBaseUrl}${dclassMap[currentDevice.product_type].code}/${getDeviceStatus(currentDevice)}.png`
}

/**
 * 获取亨特设备对应状态
 * @param {Object} states
 * @param {Object} product_type
 * @param {Object} number
 */
export function getHunterValveStatus(states, number) {
	let status = 'd_close'
	if (states && states.valves && states.valves.includes(number)) {
		status = 'd_run'
	}
	return status
}

/**
 * 获取亨特设备对应状态图片
 * @param {*} currentDevice
 * @param {*} product_type
 * @param {*} number
 * @returns
 */
export function getHunterValveImage(states, product_type, number) {
	const status = getHunterValveStatus(states, number)
	return `${resourceBaseUrl}${dclassMap[product_type].code}/${status}.png`
}

/**
 * 获取所有要订阅的设备序列号
 * @param {*} devices
 * @returns
 */
export function getMqttSerialnos(devices) {
	const serialnos = devices.map(item => item.serialno)
	const devices_has_child = devices.filter(val => {
		return val.devices && val.devices.length > 0
	})
	let result = []
	devices_has_child.forEach(item => {
		result = serialnos.concat(item.devices.map(val => val.serialno))
	})

	return result
}

/**
 * 获取设备顶部
 * @param {Object} currentDevice
 */
export function getDeviceHeader(currentDevice) {
	if (currentDevice.serialno) {
		const headerObj = {
			serialno: currentDevice.serialno,
			name: currentDevice.name,
			picture: currentDevice.picture,
			footer: currentDevice['states'] && currentDevice['states'].datatime ? currentDevice['states']
				.datatime : '',
			status: getDeviceStatus(currentDevice)
		}
		const rtuPortDisplays = currentDevice.rtuPortDisplays
		for (const item of rtuPortDisplays) {
			if (item.identity.indexOf('extra') > -1) {
				headerObj.extra = getDeviceState(currentDevice['states'][item.namekey], item, currentDevice[
						'states']) +
					item
					.unit || ''
			}
			if (item.identity.indexOf('main') > -1) {
				const name = currentDevice.serialno === '0106.0007.2133000967' ? item.name + '：' : ''
				headerObj.main = name + getDeviceState(currentDevice['states'][item.namekey], item, currentDevice[
						'states']) +
					item
					.unit
			}
		}

		return headerObj
	}
	return {}
}

// 格式化喷灌机速率
export function formatSprinklerRate(value, prefix = '00') {
	const rateHex = value.toString(16)
	let result = value > 15 ? rateHex : `0${rateHex}`;
	result = parseInt(prefix + result, 16);

	return result;
}

/**
 * 获取最后一位是特殊字符的设备serialno
 * @param {Object} serialno
 */
export function getDeviceSerialno(serialno) {
	const lastChar = serialno.slice(serialno.length - 1)
	if (!isNumber(lastChar)) {
		const arr = serialno.split('.')
		arr[2] = +(arr[2].slice(0, -1) + 9) + ASCII[lastChar]
		serialno = arr.join('.')
	}
	return serialno
}

/**
 * 1. 根据有效半径计算周长，根据周长除以轮胎转速计算100%走一圈需要时间
 * 2. 根据时间 乘以 水泵额定流量 计算总水量
 * 3. 根据总水量 除以 总面积 得出降雨量
 */
export function getRainfallByRate(rate = 100, radius, radius_valid, speed, flow) {
	if (rate) {
		const hours = 2 * Math.PI * radius_valid / speed / 60
		const waterAmount = hours * flow
		const rainfall = waterAmount / (Math.PI * Math.pow(radius, 2)) * 1000
		const result = rainfall * (100 / rate)
		return +result.toFixed(1)
	}
	return 0
}

export function getQfImage(device, port) {
	const status = getDeviceStatus(device) || 'd_close'
	return `${resourceBaseUrl}${dclassMap[101].code}/${status}.png`
}

export function getFmImage(device, port) {
	const status = getFmStatus(device, port)
	return `${resourceBaseUrl}${dclassMap[13].code}/${status}.png`
}

// export function getFmStatus(device, port) {
// 	const states = device.states
// 	let status = 'd_close'
// 	const namekey = 'a' + port
// 	if (states && states[namekey]) {
// 		status = 'd_trouble'
// 		if (Number(states[namekey]) < 100) {
// 			status = 'd_close'
// 		}
// 		if (Number(states[namekey]) > 3000) {
// 			status = 'd_run'
// 		}
// 	}
// 	return status
// }

export function getFmStatus(device, port) {
	const states = device.states
	let status = 'd_close'
	if (port > 0) {
		const namekey = 'a' + port
		if (states && states[namekey]) {
			status = 'd_trouble'
			if (Number(states[namekey]) < 100) {
				status = 'd_close'
			}
			if (Number(states[namekey]) > 3000) {
				status = 'd_run'
			}
		}
	} else {
		status = states['GateStat'] && +states['GateStat'] ? 'd_run' : 'd_close'
	}

	return status
}

export function getValveImage(device, port) {
	let status
	if (!port) {
		status = getValveStatus(device, 3) > 0 || getValveStatus(device, 4) > 0 ? 'd_run' : 'd_close'
	} else {
		status = getValveStatus(device, port) > 0 ? 'd_run' : 'd_close'
	}
	return `${resourceBaseUrl}${dclassMap[13].code}/${status}.png`
}

// export function getValveStatus(device, port) {
// 	const DO = device.states && device.states.DO
// 	const val = Math.pow(2, port - 1)
// 	return DO & val
// }

export function getValveStatus(device, port) {
	if (+port > 0) {
		const DO = (device && device.states && device.states.DO) || 0
		const val = Math.pow(2, port - 1)
		return DO & val
	}
	return (device && device.states && device.states.GateCtrlStat && +device.states.GateCtrlStat) ? 1 : 0
}

/**
 * 计算脉冲值
 * @param {*} value
 * @returns
 */
export function getPwmInfo(value) {
	const hex = (+value).toString(16)
	let cycle = 60
	let pwm = 50
	if (hex.length === 2) {
		cycle = parseInt(hex[0], 16)
		pwm = parseInt(hex[1], 16)
	}
	if (hex.length === 3) {
		cycle = parseInt(hex[0], 16)
		pwm = parseInt(hex.substr(1, 2), 16)
	}
	if (hex.length === 4) {
		cycle = parseInt(hex.substr(0, 2), 16)
		pwm = parseInt(hex.substr(2, 2), 16)
	}

	return cycle + 's | ' + pwm + '%'
}
